from marajo.appengine.handlers.db import DBHandler
from marajo.appengine.api.users import User
from marajo.appengine.ext.db import Model, Key, Property

from resources.project import Project
from resources.release import Release
from resources.component import Component
from resources.comment import Comment
from resources.client import Client
from datetime import datetime
from marajo.appengine.ext.webapp import template

import logging
log = logging.getLogger("vermouth.ticket_handler")

class TicketHandler(DBHandler):
    """
    Override to allow only specific people to edit
    specific things.
    
    For example, people must have privs to add tickets
    to projects.
    """

    def create_form(self):
        """
        Only show projects they are a member of,
        unless they are an admin
        """
        template_values = {}
        template_values['action_href'] = self.request.script_name
        template_values['action_method'] = "POST"
        template_values['types'] = self.db_class.find_property("type").choices
        template_values['projects'] = self.get_projects()
        template_values['rates'] = self.db_class.find_property("rate").choices
        
        self.display(self.create_template, template_values)

    def edit_form(self, obj):
        """
        This form basically just lets the user add comments
        """
        template_values = {}
        template_values['action_href'] = "%s/%s" % (self.request.script_name, obj.id)
        template_values['action_method'] = "POST"
        template_values['types'] = self.db_class.find_property("type").choices
        template_values['obj'] = obj
        template_values['users'] = User.find()
        template_values['statuses'] = self.db_class.find_property("status").choices
        template_values['rates'] = self.db_class.find_property("rate").choices
        template_values['clients'] = Client.find()

        self.display(self.edit_template, template_values)

    def get_projects(self):
        if self.user.has_auth_group("admin"):
            query = Project.find()
        else:
            query = Project.find(members=self.user.key())
        return query

    def search(self, search_terms):
        """
        Search for given objects
        @param search_terms: The Terms to search for
        @type search_terms: MultiDict
        """
        objects = []
        if self.user.has_auth_group("admin"):
            query = self.db_class.find()
        else:
            my_projects = [x for x in self.get_projects()]
            if len(my_projects) > 0:
                query = self.db_class.find(project = my_projects)
            else:
                return []
        for filter in set(search_terms.keys()):
            filter_value = search_terms.getall(filter)
            if len(filter_value) == 1:
                filter_value = filter_value[0]
            if filter_value:
                query.filter("%s = " % filter, filter_value)
        for obj in query:
            objects.append(obj)
        return objects

    def create(self, params):
        obj = self.db_class()
        obj.submitted_by = self.user
        props = {}
        for p in obj.properties():
            props[p.name] = p
        for param in params.keys():
            if props.has_key(param) and params.getone(param):
                prop = props[param]
                if prop.data_type == list:
                    val = [self.decode(prop.item_type, v) for v in params.getone(param).split("\r\n")]
                    log.info("%s: %s" % (param, str(val)))
                elif prop.data_type == Key:
                    val = self.decode(prop.reference_class, params.getone(param))
                    log.info("%s: %s" % (param, str(val.id)))
                else:
                    val = self.decode(prop.data_type, params.getone(param))
                    log.info("%s: %s" % (param, str(val)))
                setattr(obj, param, val)
        obj.save()
        # Notify everyone under this project
        vals = {}
        vals['appname'] = self.config.get("application")
        vals['ticket_name'] =  obj.name
        vals['ticket'] = obj
        vals['host_url'] = self.host_url

        subject = "[%(appname)s] ticket created: %(ticket_name)s" % vals
        body = template.render("notify/ticket_add.tmpl", vals)
        for usr in obj.project.members:
            usr.notify(subject=subject, body=body)

        return obj

    def update(self, obj, params):
        """
        Really what we're doing here is adding a comment
        Employee's are allowed to change the properties 
        of a ticket.
        """
        comment = Comment()
        comment.ticket = obj
        comment.owner = self.user
        comment.comment = params.get("comment")
        # Only employee's can edit ticket properties
        if self.user.has_auth_group("employee"):
            ticket_estimated_hours = int(params.get("ticket_estimated_hours"))
            if ticket_estimated_hours != obj.estimated_hours:
                comment.changes.append("<b>Estimated Hours</b> changed from %s to %s" % (obj.estimated_hours, ticket_estimated_hours))
                obj.estimated_hours = ticket_estimated_hours
            if params.get("ticket_rate") != obj.rate:
                comment.changes.append("<b>Rate</b> changed from %s to %s" % (obj.rate, params.get("ticket_rate")))
                obj.rate = params.get("ticket_rate")
            if params.get("ticket_added_hours"):
                comment.changes.append("<b>Added Hours:</b> %s" % params.get("ticket_added_hours"))
                comment.minutes = int(float(params.get("ticket_added_hours"))*60)
                obj.minutes += int(float(params.get("ticket_added_hours"))*60)
            if params.get("ticket_type") != obj.type:
                comment.changes.append("<b>Type</b> changed from %s to %s" % (obj.type, params.get("ticket_type")))
                obj.type = params.get("ticket_type")
            if params.get("ticket_owner"):
                ticket_owner = User.get_by_ids(params.get("ticket_owner"))
                if obj.owner == None or ticket_owner.id != obj.owner.id:
                    comment.changes.append("<b>Owner</b> changed from %s to %s" % (obj.owner, ticket_owner))
                    obj.owner = ticket_owner
            if params.get("ticket_status") != obj.status:
                comment.changes.append("<b>Status</b> changed from %s to %s" % (obj.status, params.get("ticket_status")))
                if params.get("ticket_status") == "closed":
                    obj.date_finished = datetime.now()
                obj.status = params.get("ticket_status")
            if params.get("ticket_release"):
                ticket_release = Release.get_by_ids(params.get("ticket_release"))
                if obj.release == None or ticket_release.id != obj.release.id:
                    comment.changes.append("<b>Release</b> changed from %s to %s" % (obj.release, ticket_release))
                    obj.release = ticket_release
            if params.get("ticket_component"):
                ticket_component = Component.get_by_ids(params.get("ticket_component"))
                if obj.component == None or ticket_component.id != obj.component.id:
                    comment.changes.append("<b>Component</b> changed from %s to %s" % (obj.component, ticket_component))
                    obj.component = ticket_component
            if params.get("clients"):
                clients = []
                for cl in params.getall("clients"):
                    clients.append(Client.get_by_ids(cl))

                if [c.id for c in obj.clients] != [c.id for c in clients]:
                     comment.changes.append("<b>Clients</b> changed")
                     obj.clients = clients

        comment.put()
        obj.put()
        # Notify creator and owner of change
        vals = {}
        vals['appname'] = self.config.get("application")
        vals['ticket_name'] =  obj.name
        vals['comment'] = comment
        vals['ticket'] = obj
        vals['host_url'] = self.host_url

        subject = "[%(appname)s] ticket updated: %(ticket_name)s" % vals
        body = template.render("notify/ticket_change.tmpl", vals)
        for usr in obj.project.members:
            usr.notify(subject=subject, body=body)

        return obj

    def delete(self):
        """
        Only admins should be able to delete tickets
        """
        if not self.user.has_auth_group("admin"):
            raise Unauthorized()
        return DBHandler.delete(self)
